﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml.Linq;
using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Services;

namespace Himp.TaskScheduling
{
    public class ActiviWorkflowManager : DomainService, IWorkflowManager
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private string _baseUrl = "http://112.33.34.123:8084/workflow";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="httpClientFactory"></param>
        public ActiviWorkflowManager(IHttpClientFactory httpClientFactory) 
        {
            _httpClientFactory = httpClientFactory;
        }

        /// <summary>
        /// 工作流模型获取
        /// </summary>
        /// <returns></returns>
        public async Task<List<WorkflowModel>> GetWorkflowModel(int? status)
        {
            List<WorkflowModel> processModels = new List<WorkflowModel>();
            var client = _httpClientFactory.CreateClient();
            var url = string.Empty;

            switch (status)
            {
                case 1: url = $"{_baseUrl}/flow/isdeloy"; break; //部署
                case 2: url = $"{_baseUrl}/flow/notdeloy"; break; //未部署
                default: url = $"{_baseUrl}/flow/actremodel"; break; //全部
            }

            var responseModel = await client.GetAsync(url);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var activiProcessModels = await responseModel.Content.ReadFromJsonAsync<List<ActiviProcessModel>>();

                foreach (var item in activiProcessModels)
                {
                    WorkflowModel processModel = new WorkflowModel(item.id_, item.name_, item.version_, item.create_TIME_);
                    processModel.LastUpdateTime = item.last_UPDATE_TIME_;
                    processModel.WorkflowModelStas = item.suspension_STATE_.HasValue ? (EnumWorkflowModelStas)item.suspension_STATE_ : EnumWorkflowModelStas.未部署;
                    processModel.DeploymentId = item.definition_Id_;
                    processModel.DeployKey = item.deploy_KEY_;
                    processModel.EditorSourceExtraValueId = item.editor_SOURCE_EXTRA_VALUE_ID_;
                    processModel.EditorSourceValueId = item.editor_SOURCE_VALUE_ID_;
                    processModels.Add(processModel);
                }
            }

            return processModels;
        }

        /// <summary>
        /// 删除工作流模型
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<WorkflowInstanceStas> DeleteWorkflowModel(string id)
        {
            WorkflowInstanceStas workflowInstanceStas = new WorkflowInstanceStas();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/flow/deleteModel";
            var req = new { modelId = id };

            var responseModel = await client.PostAsJsonAsync(url, req);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();
                workflowInstanceStas.Msg = resultString;
            }
            else
            {
                workflowInstanceStas.Code = -1;
                workflowInstanceStas.Msg = responseModel.ReasonPhrase;
            }

            return workflowInstanceStas;
        }

        /// <summary>
        /// 部署工作流模型
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<WorkflowInstanceStas> DeployWorkflowModel(string id, string workflowName)
        {
            WorkflowInstanceStas workflowInstanceStas = new WorkflowInstanceStas();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/flow/deploy";
            var req = new 
            { 
                modelId = id,
                processName = workflowName
            };

            var responseModel = await client.PostAsJsonAsync(url, req);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();
                workflowInstanceStas.Msg = resultString;
            }
            else
            {
                workflowInstanceStas.Code = -1;
                workflowInstanceStas.Msg = responseModel.ReasonPhrase;
            }

            return workflowInstanceStas;
        }

        /// <summary>
        /// 激活/挂起工作流
        /// </summary>
        /// <returns></returns>
        public async Task<WorkflowInstanceStas> ActivateWorkflowModel(string deploymentKey)
        {
            WorkflowInstanceStas workflowInstanceStas = new WorkflowInstanceStas();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/flow/activateOrPend";

            var req = new
            {
                deploymentKey
            };

            var responseModel = await client.PostAsJsonAsync(url, req);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();
                workflowInstanceStas.Msg = resultString;
            }
            else
            {
                workflowInstanceStas.Code = -1;
                workflowInstanceStas.Msg = responseModel.ReasonPhrase;
            }

            return workflowInstanceStas;
        }

        /// <summary>
        /// 获取流程实例
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public async Task<List<WorkflowInstance>> GetProcessInstance(string startTime, string endTime, EnumWorkflowInstanceStas status)
        {
            List<WorkflowInstance> processInstances = new List<WorkflowInstance>();
            var client = _httpClientFactory.CreateClient();
            var url = string.Empty;

            switch (status)
            {
                case EnumWorkflowInstanceStas.激活: url = $"{_baseUrl}/monitor/queryactive"; break; //激活
                case EnumWorkflowInstanceStas.挂起: url = $"{_baseUrl}/monitor/querypend"; break; //挂起
                case EnumWorkflowInstanceStas.完成: url = $"{_baseUrl}/monitor/completed"; break; //完成
                default: url = $"{_baseUrl}/monitor/queryactive"; break; //激活
            }

            var reqPars = new
            {
                startTime,
                endTime,
            };

            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(reqPars), null, "application/json");
            var responseModel = await client.SendAsync(request);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var activiProcessModels = await responseModel.Content.ReadFromJsonAsync<List<ActivitiProcessInstance>>();

                foreach (var item in activiProcessModels)
                {
                    //获取流程模型对应的类别
                    WorkflowInstance workflowInstance = new WorkflowInstance();
                    workflowInstance.Id = item.id;
                    workflowInstance.ProcessInstanceId = item.ProcessInstanceId;
                    workflowInstance.Begintime = item.processStartTime;
                    workflowInstance.Fintime = item.processEndTime;
                    workflowInstance.WorkflowModelKey = item.modelId;
                    workflowInstance.WorkflowInstanceName = item.modelName;
                    workflowInstance.WorkflowInstanceContdesc = Newtonsoft.Json.JsonConvert.SerializeObject(item.variableMap);
                    StringBuilder workflowInstanceContdescSb = new StringBuilder();

                    foreach (var variableMap in item.variableMap)
                    {
                        var key = variableMap.Key;
                        StringBuilder valueSB = new StringBuilder();
                        var je = (JsonElement)variableMap.Value;
                        List<WorkflowTypeStColumn> workflowTypeStColumns = new List<WorkflowTypeStColumn>();

                        var workflowTypeStColumn = workflowTypeStColumns.FirstOrDefault(w => w.Index == key);

                        if (workflowTypeStColumn != null)
                        {
                            workflowInstanceContdescSb.Append(workflowTypeStColumn.Title);
                        }
                        else
                        {
                            workflowInstanceContdescSb.Append(key);
                        }

                        workflowInstanceContdescSb.Append("：");

                        if (je.ValueKind == JsonValueKind.Array)
                        {
                            foreach (JsonElement element in je.EnumerateArray())
                            {
                                workflowInstanceContdescSb.Append(" ");
                                workflowInstanceContdescSb.Append(element.ToString());
                            }
                        }
                        else
                        {
                            workflowInstanceContdescSb.Append(je.ToString());
                        }

                        workflowInstanceContdescSb.AppendLine(" ");
                    }

                    workflowInstance.WorkflowInstanceContdesc = workflowInstanceContdescSb.ToString();
                    workflowInstance.CurrNodeCodg = item.taskId;
                    workflowInstance.CurrNodeName = item.taskName;
                    workflowInstance.WorkflowInstanceStas = (EnumWorkflowInstanceStas)item.suspensionCode;

                    processInstances.Add(workflowInstance);
                }
            }

            return processInstances;
        }

        /// <summary>
        /// 获取流程实例
        /// </summary>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="status"></param>
        /// <returns></returns>
        public async Task<List<WorkflowTodoTask>> GetTodoTask(string userId)
        {
            List<WorkflowTodoTask> processInstances = new List<WorkflowTodoTask>();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/audit/notaudit";
            var reqPars = new
            {
                workId = userId
            };

            var request = new HttpRequestMessage(HttpMethod.Get, url);
            request.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(reqPars), null, "application/json");
            var responseModel = await client.SendAsync(request);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                processInstances = await responseModel.Content.ReadFromJsonAsync<List<WorkflowTodoTask>>();
            }

            return processInstances;
        }

        /// <summary>
        /// 启动工作流程实例
        /// </summary>
        /// <param name="processDefinitionId"></param>
        /// <param name="assocUsers"></param>
        /// <param name="startId"></param>
        /// <param name="bizPars"></param>
        /// <returns></returns>
        public async Task<WorkflowInstanceStas> StartWorkflowInstance(string processDefinitionId, Dictionary<string, List<string>> assocUsers, string startId, Dictionary<string, object> bizPars)
        {
            WorkflowInstanceStas res = new WorkflowInstanceStas();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/application/start";

            Dictionary<string, object> reqPars = new Dictionary<string, object>();
            reqPars.Add("startId", startId);
            reqPars.Add("processDefinitionId", processDefinitionId);
            reqPars.Add("groupCode", assocUsers);
            reqPars.Add("businessVariables", bizPars);

            var responseModel = await client.PostAsJsonAsync(url, reqPars);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();
                res.Msg = resultString;

                return res;
            }
            else
            {
                res.Code = -1;
                res.Msg = responseModel.ReasonPhrase;
                return res;
            }
        }

        /// <summary>
        /// 流程执行
        /// </summary>
        /// <param name="processInstanceId"></param>
        /// <param name="userId"></param>
        /// <param name="bizPars"></param>
        /// <returns></returns>
        public async Task<WorkflowInstanceStas> ExecWorkflowInstance(string processInstanceId, string userId, Dictionary<string, object> bizPars)
        {
            WorkflowInstanceStas res = new WorkflowInstanceStas();
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/monitor/claimTask";

            Dictionary<string, object> reqPars = new Dictionary<string, object>();
            reqPars.Add("processinstanceid", processInstanceId);
            reqPars.Add("workId", userId);
            reqPars.Add("businessVariables", bizPars);

            var responseModel = await client.PostAsJsonAsync(url, reqPars);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();
                res.Msg = resultString;

                return res;
            }
            else
            {
                res.Code = -1;
                res.Msg = responseModel.ReasonPhrase;
                return res;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        public async Task<List<WorkflowInstance>> GetProcessInstance(EnumWorkflowInstanceStas status)
        {
            List<WorkflowInstance> processInstances = new List<WorkflowInstance>();
            var client = _httpClientFactory.CreateClient();
            var url = string.Empty;

            switch (status)
            {
                case EnumWorkflowInstanceStas.激活: url = $"{_baseUrl}/monitor/queryactive"; break; //激活
                case EnumWorkflowInstanceStas.挂起: url = $"{_baseUrl}/monitor/querypend"; break; //挂起
                case EnumWorkflowInstanceStas.完成: url = $"{_baseUrl}/monitor/completed"; break; //完成
                default: url = $"{_baseUrl}/monitor/queryactive"; break; //激活
            }

            var responseModel = await client.GetAsync(url);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var activiProcessModels = await responseModel.Content.ReadFromJsonAsync<List<ActivitiProcessInstance>>();
                
                foreach (var item in activiProcessModels)
                {
                    //获取流程模型对应的类别
                    WorkflowInstance workflowInstance = new WorkflowInstance();
                    workflowInstance.Id = item.id;
                    workflowInstance.ProcessInstanceId = item.ProcessInstanceId;
                    workflowInstance.Begintime = item.processStartTime;
                    workflowInstance.Fintime = item.processEndTime;
                    workflowInstance.WorkflowModelKey = item.modelId;
                    workflowInstance.WorkflowInstanceName = item.modelName;
                    workflowInstance.WorkflowInstanceContdesc = Newtonsoft.Json.JsonConvert.SerializeObject(item.variableMap);
                    StringBuilder workflowInstanceContdescSb = new StringBuilder();
                    //var workflowModelAssocType = workflowModelAssocTypeQuery.FirstOrDefault(w => w.WorkflowModeId == item.modelId);

                    foreach (var variableMap in item.variableMap)
                    {
                        var key = variableMap.Key;
                        StringBuilder valueSB = new StringBuilder();
                        var je = (JsonElement)variableMap.Value;
                        List<WorkflowTypeStColumn> workflowTypeStColumns = new List<WorkflowTypeStColumn>();

                        //if (workflowModelAssocType != null)
                        //{
                        //    workflowTypeStColumns = workflowModelAssocType.WorkflowType.GetStColumns();
                        //}

                        var workflowTypeStColumn = workflowTypeStColumns.FirstOrDefault(w => w.Index == key);

                        if (workflowTypeStColumn != null)
                        {
                            workflowInstanceContdescSb.Append(workflowTypeStColumn.Title);
                        }
                        else
                        {
                            //continue;
                            workflowInstanceContdescSb.Append(key);
                        }

                        workflowInstanceContdescSb.Append("：");

                        if (je.ValueKind == JsonValueKind.Array)
                        {
                            foreach (JsonElement element in je.EnumerateArray())
                            {
                                workflowInstanceContdescSb.Append(" ");
                                workflowInstanceContdescSb.Append(element.ToString());
                            }
                        }
                        else
                        {
                            workflowInstanceContdescSb.Append(je.ToString());
                        }

                        workflowInstanceContdescSb.AppendLine("。");
                    }

                    workflowInstance.WorkflowInstanceContdesc = workflowInstanceContdescSb.ToString();
                    workflowInstance.CurrNodeCodg = item.taskId;
                    workflowInstance.CurrNodeName = item.taskName;
                    workflowInstance.WorkflowInstanceStas = (EnumWorkflowInstanceStas)item.suspensionCode;

                    processInstances.Add(workflowInstance);
                }
            }

            return processInstances;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deployKey"></param>
        /// <param name="pars"></param>
        /// <returns></returns>
        public async Task<string> FinishWorkflowInstance(string workflowInstanceId, string userId)
        {
            var client = _httpClientFactory.CreateClient();
            var url = $"{_baseUrl}/monitor/claimTask";
            var req = new
            {
                processinstanceid = workflowInstanceId,
                workId = userId
            };

            var responseModel = await client.PostAsJsonAsync(url, req);

            if (responseModel.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var resultString = await responseModel.Content.ReadAsStringAsync();

                return resultString;
            }
            else
            {
                return string.Empty;
            }
        }
    }

    public class WorkflowInstanceStas
    {
        public int Code { get; set; }

        public string Msg { get; set; }
    }
}
